﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Entidades.Seguridad;
using Entidades.Sistema.Base;
using Entidades.Sistema.Venta;
using Entidades.Sistema.Distribucion;
using Entidades.Sistema.Distribucion.CoR;
using Modelo.Sistema.Distribucion;
using Modelo.Sistema.Venta;
using Modelo.Sistema.Base;
using DevExpress.XtraPrinting.InternalAccess;
using DevExpress.XtraReports.UI;
using DevExpress.Web.ASPxEditors;
using DevExpress.Web.Mvc;
using System.Web.Script.Serialization;
using System.Globalization;
using System.Threading;
using System.Net;
using System.Text;

namespace VistaOnlineR1._1.Controllers.Sistema.Distribucion
{
    public class DiagramacionDistribucionController : BaseController
    {
        #region campos
        CatalogoDiagramacionDistribucion _catalogoDiagramacionDistribucion;
        CatalogoEmpleado _catalogoEmpleado;
        CatalogoVehiculo _catalogoVehiculo;
        CatalogoPedidos _catalogoPedidos;
        CatalogoZona _catalogoZonas;
        CatalogoCliente _catalogoCliente;

        public object CheckedValues { get; set; }
        #endregion

        #region Constructors
        public DiagramacionDistribucionController()
            : this(new CatalogoDiagramacionDistribucion(), 
                    new CatalogoPedidos(),
                    new CatalogoVehiculo(),
                    new CatalogoEmpleado(),
                    new CatalogoZona(),
            new CatalogoCliente())
        {
        }

        public DiagramacionDistribucionController(CatalogoDiagramacionDistribucion catalogoDiagramacionDistribucion, 
                                                    CatalogoPedidos catalogoPedidos,
                                                    CatalogoVehiculo catalogoVehiculo,
                                                    CatalogoEmpleado catalogoEmpleado,
                                                    CatalogoZona catalogoZona,
                                                    CatalogoCliente catalogoCliente)
        {
            _catalogoDiagramacionDistribucion = catalogoDiagramacionDistribucion;
            _catalogoPedidos = catalogoPedidos;
            _catalogoVehiculo = catalogoVehiculo;
            _catalogoEmpleado = catalogoEmpleado;
            _catalogoZonas = catalogoZona;
            _catalogoCliente = catalogoCliente;
        }
        #endregion

        public ActionResult Index()
        {
            List<Perfil> perfiles = RecuperarPerfil();

            ViewBag.PermisoDelete = perfiles.Exists(per => per.Permiso.Nombre == "Delete");
            ViewBag.PermisoCreate = perfiles.Exists(per => per.Permiso.Nombre == "Create");
            ViewBag.PermisoEdit = perfiles.Exists(per => per.Permiso.Nombre == "Edit");

            return View(_catalogoDiagramacionDistribucion.ListarDiagramacionDistribucion());
        }

        [ValidateInput(false)]
        public ActionResult EditDiagramacionDistribucionPartial()
        {
            List<Perfil> perfiles = RecuperarPerfil();

            ViewBag.PermisoDelete = perfiles.Exists(per => per.Permiso.Nombre == "Delete");
            ViewBag.PermisoCreate = perfiles.Exists(per => per.Permiso.Nombre == "Create");
            ViewBag.PermisoEdit = perfiles.Exists(per => per.Permiso.Nombre == "Edit");

            ViewBag.Vehiculo = _catalogoVehiculo.ListarVehiculo();

            return PartialView("EditDiagramacionDistribucionPartial", _catalogoDiagramacionDistribucion.ListarDiagramacionDistribucion());
        }

        public ActionResult EditDiagramacionDistribucionDetallePartial()
        {
            string idsession = "DiagramacionDistribucion";
            DiagramacionDistribucion diagramacionDistribucion = (DiagramacionDistribucion)System.Web.HttpContext.Current.Session[idsession];
            ViewBag.Empleado = _catalogoEmpleado.Listarempleados();
            ViewBag.Vehiculo = _catalogoVehiculo.ListarVehiculo();
            

            return PartialView("EditDiagramacionDistribucionDetallePartial", diagramacionDistribucion.Detalle);
        }



        //Imprimir
        public ActionResult ImprimirDiagramacion(int IdDiagramacionDistribucion)
        {
            string idsession = "DiagramacionAImprimir";
            DiagramacionDistribucion oDiagramacionDistribucion = new DiagramacionDistribucion();
            oDiagramacionDistribucion = _catalogoDiagramacionDistribucion.BuscarDiagramacionDistribucion(IdDiagramacionDistribucion);
            System.Web.HttpContext.Current.Session[idsession] = oDiagramacionDistribucion;
            return View();
        }
        public ActionResult ImprimirDiagramacionPartial()
        {
            string idsession = "DiagramacionAImprimir";
            string idsessionreporte = "Reporte";
            DiagramacionDistribucion oDiagramacionDistribucion = (DiagramacionDistribucion)System.Web.HttpContext.Current.Session[idsession];
            Reportes.rptDiagramaciondistribucion rpt = new Reportes.rptDiagramaciondistribucion();

            rpt.DataSource = _catalogoDiagramacionDistribucion.ListarDiagramacionDistribucion().Where(x => x.IdDiagramacionDistribucion == oDiagramacionDistribucion.IdDiagramacionDistribucion).ToList();
            ViewData["Report"] = rpt;
            System.Web.HttpContext.Current.Session[idsessionreporte] = rpt;

            return PartialView("ImprimirDiagramacionPartial");
        }
        public ActionResult ImprimirDiagramacionPartialExportTo()
        {
            string idsessionreporte = "Reporte";
            Reportes.rptDiagramaciondistribucion rpt = (Reportes.rptDiagramaciondistribucion)System.Web.HttpContext.Current.Session[idsessionreporte];
            return DocumentViewerExtension.ExportTo(rpt);
        }

        public ActionResult DiagramacionResultantePartial(int IdDiagramacionDistribucion)
        {
            ViewData["IdDiagramacionDistribucion"] = IdDiagramacionDistribucion;
            return PartialView("DiagramacionResultantePartial", _catalogoDiagramacionDistribucion.ListarDiagramacionDistribucion().FirstOrDefault(x => x.IdDiagramacionDistribucion == IdDiagramacionDistribucion).Detalle);
        }

        public ActionResult PedidosPartial(int IdDiagramacionDistribucionDetalle)
        {
            string idsession = "DiagramacionDistribucion";
            DiagramacionDistribucion diagramacionDistribucion = (DiagramacionDistribucion)System.Web.HttpContext.Current.Session[idsession];

            ViewBag.Empleado = _catalogoEmpleado.Listarempleados();
            ViewBag.Vehiculo = _catalogoVehiculo.ListarVehiculo();
            ViewBag.Cliente = _catalogoCliente.ListarCliente();

            if (diagramacionDistribucion != null)
            {
                return PartialView("PedidosPartial", diagramacionDistribucion.Detalle.FirstOrDefault(x => x.IdDiagramacionDistribucionDetalle == IdDiagramacionDistribucionDetalle).Pedidos);
            }
            else
            {
                return PartialView("PedidosPartial", _catalogoDiagramacionDistribucion.ListarDiagramacionDistribucion().FirstOrDefault().Detalle.FirstOrDefault( y => y.IdDiagramacionDistribucionDetalle == IdDiagramacionDistribucionDetalle).Pedidos);
            }            
        }

        [HttpGet]
        public ActionResult EditDiagramacionDistribucionUpdatePartial(int IdDiagramacionDistribucion)
        {
            string idsession = "DiagramacionDistribucion";
            DiagramacionDistribucion editDiagramacionDistribucion = new DiagramacionDistribucion();

            if (IdDiagramacionDistribucion == -1)
            {
                ViewBag.TabInicio = true;
                ViewBag.TabPedidos = false;
                ViewBag.TabConfiguracion = false;
                ViewBag.TabResutado = false;
                editDiagramacionDistribucion.IdDiagramacionDistribucion = -1;
                editDiagramacionDistribucion.Fecha = DateTime.Now;
            }
            else
            {
                ViewBag.TabInicio = false;
                ViewBag.TabPedidos = true;
                ViewBag.TabConfiguracion = true;
                ViewBag.TabResutado = false;
                ViewBag.NoExistenPedidos = true;

                editDiagramacionDistribucion = _catalogoDiagramacionDistribucion.BuscarDiagramacionDistribucion(IdDiagramacionDistribucion);

                System.Web.HttpContext.Current.Session[idsession] = editDiagramacionDistribucion;
            }
            ViewBag.Vehiculo = _catalogoVehiculo.ListarVehiculo();
            return View("EditingFormTab", editDiagramacionDistribucion);
        }

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult PostInicioPartial(DiagramacionDistribucion DiagramacionDistribucion)
        {
            ViewBag.TabInicio = false;
            ViewBag.TabConfiguracion = true;
            ViewBag.TabResutado = false;
            ViewBag.NoExistenPedidos = true;
            ViewBag.Vehiculo = _catalogoVehiculo.ListarVehiculo();

            if (_catalogoDiagramacionDistribucion.ListarDiagramacionDistribucion().Any(x => x.Fecha.Date == DiagramacionDistribucion.Fecha.Date))
            {
                ViewBag.TabInicio = true;
                ViewBag.TabConfiguracion = false;
                ViewBag.TabResutado = false;

                ViewBag.Message = "Ya existe una digramación de distribucion para la fecha seleccionada.";

                return View("EditingFormTab", DiagramacionDistribucion);
            }

            //Reviasr los casos que son parcialmente diagramados
            List<Pedido> pedidos = _catalogoPedidos.ListarPedidos().Where(
                        x => x.FechaEntrega.Date == DiagramacionDistribucion.Fecha.Date
                        && (x.Estado == PedidosEstado.Producido || x.Estado == PedidosEstado.ParcProducido || x.Estado == PedidosEstado.PendienteEntrega)).ToList();

            if (pedidos.Count == 0)
            {
                ViewBag.TabInicio = true;
                ViewBag.TabConfiguracion = false;
                ViewBag.TabResutado = false;
                ViewBag.NoExistenPedidos = false;
                ViewBag.Message = "No se encontraron pedidos para la fecha selecciona.";
            }

            foreach (Pedido p in pedidos)
            {
                //Valildar en caso de que el barrio no este asignado a ningún barrio.
                //En el caso de que el barrio del cliente no tenga una zona asignada,  no lo agrego a la diagramacion
                //Según el item anterior deberiamos agregar una lista de pedidos sin asignacion.
                Zona z = _catalogoZonas.ListarZona().FirstOrDefault(x => x.Barrios.Any(y => y.IdBarrio == p.Cliente.Barrio.IdBarrio));
                
                if (z != null)
                {
                    Empleado e = z.Empleado;

                    if (DiagramacionDistribucion.Detalle.Any(x => x.Empleado.IdEmpleado == e.IdEmpleado))
                    {
                        DiagramacionDistribucion.Detalle.FirstOrDefault(x => x.Empleado.IdEmpleado == e.IdEmpleado).AgregarPedido(p);
                    }
                    else
                    {
                        DiagramacionDistribucionDetalle det = new DiagramacionDistribucionDetalle();
                        det.Empleado = e;
                        det.IdDiagramacionDistribucionDetalle = det.Empleado.IdEmpleado;
                        
                        det.AgregarPedido(p);
                        DiagramacionDistribucion.AgregarDetalle(det);
                    }                
                }                
            }

            //Recorrer los pedidos e ir asignado según el Empleado asignado al barrio del pedido y según el tipo de servicio de despacho.
            //Calculo según el pedido el tipo de servicio.
            //Obtengo la zona según el barrio del cliente, para cada pedido.
            //Calcular el detalle de la diagramacion según el tipo de servicio de despacho y según el empleado asginado.

            ManejadorDespacho servicioDespacho;
            TipoDeServicio tipodeservicio;

            foreach (DiagramacionDistribucionDetalle det in DiagramacionDistribucion.Detalle)
            {
                decimal pesoTotalCargaGramos = det.Pedidos.Sum(x => x.DetallePedidos.Sum(y => y.Cantidad * y.Producto.PesoNeto));
                decimal pesoTotalKilos = pesoTotalCargaGramos / 1000;

                servicioDespacho = PoliticaServicioDespacho.ServicioPreferido();
                decimal distamayor = 0;
                foreach (Pedido ped in det.Pedidos)
                {
                    decimal dist = Distancia(ped.Cliente);
                    if (dist > distamayor)
                    {
                        distamayor = dist;
                    }
                }

                tipodeservicio = servicioDespacho.Enviar(pesoTotalKilos, distamayor);
                if (tipodeservicio.retorno)
                {
                    List<Vehiculo> vehiculos = new List<Vehiculo>();
                    foreach (Vehiculo v in _catalogoVehiculo.ListarVehiculo().Where(x => x.TipoServicioDespacho == tipodeservicio.servicio))
                    {
                        if(!DiagramacionDistribucion.Detalle.Any(x => x.Vehiculo.IdVehiculo == v.IdVehiculo))
                        {
                            vehiculos.Add(v);
                        }
                    }
                    if(vehiculos.Count > 0)
                    {
                        DiagramacionDistribucion.Detalle.FirstOrDefault(x => x.IdDiagramacionDistribucionDetalle == det.IdDiagramacionDistribucionDetalle).Vehiculo = vehiculos.FirstOrDefault(x => x.TipoServicioDespacho == tipodeservicio.servicio);
                    }                    
                }
            }

            string idsession = "DiagramacionDistribucion";
            System.Web.HttpContext.Current.Session[idsession] = DiagramacionDistribucion;

            return View("EditingFormTab", DiagramacionDistribucion);
        }
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult PostConfiguracionPartial(DiagramacionDistribucion DiagramacionDistribucion)
        {
            //Esto es para poder persistir luego al finalizar la digramacion
            string idsession = "DiagramacionDistribucion";
            DiagramacionDistribucion diagramacionDistribucion = (DiagramacionDistribucion)System.Web.HttpContext.Current.Session[idsession];
            ViewBag.TabInicio = false;
            ViewBag.TabConfiguracion = false;
            ViewBag.TabResutado = true;
            ViewBag.Error = null;
            ViewBag.Vehiculo = _catalogoVehiculo.ListarVehiculo();

            if (diagramacionDistribucion.Detalle.Any(x => x.Vehiculo == null || x.Vehiculo.IdVehiculo == 0))
            {
                ViewBag.TabConfiguracion = true;
                ViewBag.TabResutado = false;

                ViewBag.Error = "Existen diagramaciones sin vehiculo asignado";
                return View("EditingFormTab", diagramacionDistribucion);
            }

            if (diagramacionDistribucion != null)
            {
                if (diagramacionDistribucion.IdDiagramacionDistribucion == -1)
                {
                    diagramacionDistribucion.Estado = DiagramacionDistribucion.DiagramacionDistribucionEstado.Creado;
                    _catalogoDiagramacionDistribucion.AgregarDiagramacionDistribucion(diagramacionDistribucion);
                }
                else
                {
                    diagramacionDistribucion.Estado = DiagramacionDistribucion.DiagramacionDistribucionEstado.Editada;
                    _catalogoDiagramacionDistribucion.ModificarDiagramacionDistribucion(diagramacionDistribucion);
                }
                foreach (DiagramacionDistribucionDetalle d in diagramacionDistribucion.Detalle)
                {
                    foreach (Pedido oPedido in d.Pedidos)
                    {
                        oPedido.Estado = PedidosEstado.PendienteEntrega;
                        _catalogoPedidos.ModificarPedido(oPedido);
                    }
                }
            }

            return View("EditingFormTab", diagramacionDistribucion);
        }

        public ActionResult EditDiagramacionDistribucionDetalleUpdatePartial(MVCxGridViewBatchUpdateValues<DiagramacionDistribucionDetalle, int> updateValues)
        {
            string idsession = "DiagramacionDistribucion";
            DiagramacionDistribucion diagramacionDistribucion = (DiagramacionDistribucion)System.Web.HttpContext.Current.Session[idsession];

            foreach (DiagramacionDistribucionDetalle d in updateValues.Update)
            {
                Vehiculo v = _catalogoVehiculo.BuscarVehiculo(d.Vehiculo.IdVehiculo);
                diagramacionDistribucion.Detalle.FirstOrDefault(x => x.IdDiagramacionDistribucionDetalle == d.IdDiagramacionDistribucionDetalle).Vehiculo = v;
            }

            System.Web.HttpContext.Current.Session[idsession] = diagramacionDistribucion;

            ViewBag.Empleado = _catalogoEmpleado.Listarempleados();
            ViewBag.Vehiculo = _catalogoVehiculo.ListarVehiculo();

            return PartialView("EditDiagramacionDistribucionDetallePartial", diagramacionDistribucion.Detalle);
        }

        public ActionResult EditDiagramacionDistribucionDeletePartial(int IdDiagramacionDistribucion)
        {
            DiagramacionDistribucion editDiagramacionDistribucion = new DiagramacionDistribucion();
            editDiagramacionDistribucion = _catalogoDiagramacionDistribucion.BuscarDiagramacionDistribucion(IdDiagramacionDistribucion);
            _catalogoDiagramacionDistribucion.EliminarDiagramacionDistribucion(editDiagramacionDistribucion);


            foreach (DiagramacionDistribucionDetalle d in editDiagramacionDistribucion.Detalle)
            {
                foreach (Pedido oPedido in d.Pedidos)
                {
                    oPedido.Estado = PedidosEstado.PendienteEntrega;
                    _catalogoPedidos.ModificarPedido(oPedido);
                }
            }

            List<Perfil> perfiles = RecuperarPerfil();

            ViewBag.PermisoDelete = perfiles.Exists(per => per.Permiso.Nombre == "Delete");
            ViewBag.PermisoCreate = perfiles.Exists(per => per.Permiso.Nombre == "Create");
            ViewBag.PermisoEdit = perfiles.Exists(per => per.Permiso.Nombre == "Edit");

  //          ViewBag.Vehiculo = _catalogoVehiculo.ListarVehiculo();
            ViewBag.Estado = "La diagramacion de Distribucion se cancelo con exito";
            return View();
        }


        public ActionResult ConfirmarEntrega(int IdDiagramacionDistribucion)
        {
            DiagramacionDistribucion editDiagramacionDistribucion = new DiagramacionDistribucion();
            editDiagramacionDistribucion = _catalogoDiagramacionDistribucion.BuscarDiagramacionDistribucion(IdDiagramacionDistribucion);
            editDiagramacionDistribucion.Estado = DiagramacionDistribucion.DiagramacionDistribucionEstado.Finalizada;
            _catalogoDiagramacionDistribucion.SetConfirmada(editDiagramacionDistribucion);


            foreach (DiagramacionDistribucionDetalle d in editDiagramacionDistribucion.Detalle)
            {
                foreach (Pedido oPedido in d.Pedidos)
                {
                    oPedido.Estado = PedidosEstado.Entregado;
                    _catalogoPedidos.ModificarPedido(oPedido);
                }
            }

            List<Perfil> perfiles = RecuperarPerfil();

            ViewBag.PermisoDelete = perfiles.Exists(per => per.Permiso.Nombre == "Delete");
            ViewBag.PermisoCreate = perfiles.Exists(per => per.Permiso.Nombre == "Create");
            ViewBag.PermisoEdit = perfiles.Exists(per => per.Permiso.Nombre == "Edit");

            //          ViewBag.Vehiculo = _catalogoVehiculo.ListarVehiculo();
            ViewBag.Estado = "La diagramacion de Distribucion se confirmo con exito";
            return View();
        }


        public decimal Distancia(Cliente cliente)
        {
            decimal retorno = 0;

            try
            {
                using (var client = new WebClient())
                {
                    string destino = string.Format("{0}+{1}+{2}+{3}+{4}", "Argentina", cliente.Barrio.Localidad.Provincia.Nombre, cliente.Barrio.Localidad.Nombre, cliente.Barrio.Nombre, cliente.Direccion);

                    var values = HttpUtility.ParseQueryString(string.Empty);
                    values["origins"] = "Argentina+Santa+fe+fray+luis+beltran+Ricchieri+237";
                    //values["destinations"] = "Argentina+Santa+fe+capitan+bermudez+cristobal+colon+500";
                    values["destinations"] = destino;
                    values["language"] = "es-AR";
                    values["sensor"] = "false";

                    var uriBuilder = new UriBuilder("http://maps.googleapis.com/maps/api/distancematrix/json");
                    uriBuilder.Query = values.ToString();
                    var result = client.DownloadData(uriBuilder.ToString());
                    var json = Encoding.UTF8.GetString(result);

                    var serializer = new JavaScriptSerializer();
                    var distanceResponse = serializer.Deserialize<DistanceResponse>(json);
                    if (string.Equals("ok", distanceResponse.Status, StringComparison.OrdinalIgnoreCase))
                    {
                        //Console.WriteLine("origin addresses: {0}", string.Join(", ", distanceResponse.Origin_Addresses));
                        //Console.WriteLine("destination addresses: {0}", string.Join(", ", distanceResponse.Destination_Addresses));
                        foreach (var row in distanceResponse.Rows)
                        {
                            foreach (var element in row.Elements)
                            {
                                if (string.Equals("ok", element.Status, StringComparison.OrdinalIgnoreCase))
                                {
                                    retorno = Convert.ToDecimal(element.Distance.Text.Replace(" km", ""));
                                }
                            }
                        }
                    }
                }

                return retorno;
            }
            catch (WebException we)
            {
                return 0;
            }            
        }        
    }

    public class DistanceResponse
    {
        public string Status { get; set; }
        public string[] Origin_Addresses { get; set; }
        public string[] Destination_Addresses { get; set; }
        public Row[] Rows { get; set; }
    }

    public class Row
    {
        public Element[] Elements { get; set; }
    }

    public class Element
    {
        public string Status { get; set; }
        public Item Duration { get; set; }
        public Item Distance { get; set; }
    }

    public class Item
    {
        public int Value { get; set; }
        public string Text { get; set; }
    }
}
